package com.zenithmind.coding.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zenithmind.common.context.UserContext;
import com.zenithmind.common.exception.BusinessException;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.common.utils.BeanCopyUtils;
import com.zenithmind.coding.mapper.ProblemMapper;
import com.zenithmind.coding.mapper.ProblemMapper.ProblemStatistics;
import com.zenithmind.coding.mapper.ProblemMapper.TagStatistics;
import com.zenithmind.coding.mapper.ProblemMapper.UserSolveStatistics;
import com.zenithmind.coding.pojo.dto.ProblemCreateDTO;
import com.zenithmind.coding.pojo.entity.Problem;
import com.zenithmind.coding.pojo.entity.TestCase;
import com.zenithmind.coding.pojo.vo.ProblemVO;
import com.zenithmind.coding.service.ProblemService;
import com.zenithmind.coding.service.TestCaseService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 编程问题服务实现类
 * 
 * @author ZenithMind Team
 * @since 2025-01-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> implements ProblemService {

    private final ProblemMapper problemMapper;
    private final TestCaseService testCaseService;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ObjectMapper objectMapper;

    private static final String PROBLEM_CACHE_KEY = "problem:detail:";
    private static final String HOT_PROBLEMS_CACHE_KEY = "problems:hot";
    private static final long CACHE_EXPIRE_TIME = 30; // 缓存过期时间（分钟）

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProblemVO createProblem(ProblemCreateDTO createDTO) {
        // 获取当前用户信息
        String currentUserId = UserContext.getUserId();
        String currentUserName = UserContext.getUsername();
        
        if (!StringUtils.hasText(currentUserId)) {
            throw new BusinessException("用户未登录");
        }

        // 创建问题实体
        Problem problem = new Problem();
        problem.setTitle(createDTO.getTitle());
        problem.setDescription(createDTO.getDescription());
        problem.setInputDescription(createDTO.getInputDescription());
        problem.setOutputDescription(createDTO.getOutputDescription());
        problem.setSampleInput(createDTO.getSampleInput());
        problem.setSampleOutput(createDTO.getSampleOutput());
        problem.setHint(createDTO.getHint());
        problem.setSource(createDTO.getSource());
        problem.setCategoryId(createDTO.getCategoryId());
        problem.setDifficulty(createDTO.getDifficulty());
        problem.setType(createDTO.getType());
        problem.setTimeLimit(createDTO.getTimeLimit());
        problem.setMemoryLimit(createDTO.getMemoryLimit());
        problem.setIsSpecialJudge(createDTO.getIsSpecialJudge());
        problem.setSpecialJudgeCode(createDTO.getSpecialJudgeCode());
        problem.setIsPublic(createDTO.getIsPublic());
        problem.setIsRecommend(createDTO.getIsRecommend());
        problem.setSortOrder(createDTO.getSortOrder());
        problem.setCreatorId(currentUserId);
        problem.setCreatorName(currentUserName);

        // 处理标签
        if (createDTO.getTags() != null && !createDTO.getTags().isEmpty()) {
            try {
                problem.setTags(objectMapper.writeValueAsString(createDTO.getTags()));
            } catch (JsonProcessingException e) {
                log.error("标签序列化失败", e);
            }
        }

        // 处理支持的编程语言
        if (createDTO.getSupportedLanguages() != null && !createDTO.getSupportedLanguages().isEmpty()) {
            try {
                problem.setSupportedLanguages(objectMapper.writeValueAsString(createDTO.getSupportedLanguages()));
            } catch (JsonProcessingException e) {
                log.error("支持语言序列化失败", e);
            }
        }

        // 设置初始统计数据
        problem.setSubmitCount(0L);
        problem.setAcceptCount(0L);
        problem.setAcceptRate(0.0);
        problem.setAvgTime(0);
        problem.setAvgMemory(0);
        problem.setRating(0.0);

        // 设置状态
        if (createDTO.getPublishNow() == 1) {
            problem.setStatus(1); // 已发布
        } else {
            problem.setStatus(0); // 草稿
        }

        // 保存问题
        boolean saved = save(problem);
        if (!saved) {
            throw new BusinessException("创建问题失败");
        }

        // 创建测试用例
        if (createDTO.getTestCases() != null && !createDTO.getTestCases().isEmpty()) {
            for (int i = 0; i < createDTO.getTestCases().size(); i++) {
                ProblemCreateDTO.TestCaseDTO testCaseDTO = createDTO.getTestCases().get(i);
                
                TestCase testCase = new TestCase();
                testCase.setProblemId(problem.getId());
                testCase.setCaseNumber(i + 1);
                testCase.setInputData(testCaseDTO.getInputData());
                testCase.setExpectedOutput(testCaseDTO.getExpectedOutput());
                testCase.setType(testCaseDTO.getType());
                testCase.setWeight(testCaseDTO.getWeight());
                testCase.setIsPublic(testCaseDTO.getIsPublic());
                testCase.setDescription(testCaseDTO.getDescription());
                testCase.setCreatorId(currentUserId);
                testCase.setCreatorName(currentUserName);
                testCase.setSortOrder(i);
                
                testCaseService.save(testCase);
            }
        }

        log.info("用户 {} 创建了问题 {}", currentUserName, problem.getTitle());
        
        return convertToVO(problem, currentUserId);
    }

    @Override
    public PageResult<ProblemVO> getProblemPage(Long current, Long size, String categoryId,
                                               Integer difficulty, Integer type, Integer status,
                                               String keyword, List<String> tags) {
        Page<Problem> page = new Page<>(current, size);
        IPage<Problem> problemPage = problemMapper.selectProblemPage(page, categoryId, difficulty, 
                                                                    type, status, keyword, tags);
        
        String currentUserId = UserContext.getUserId();
        List<ProblemVO> records = problemPage.getRecords().stream()
                .map(problem -> convertToVO(problem, currentUserId))
                .toList();
        
        return new PageResult<>(records, problemPage.getTotal(), problemPage.getCurrent(), problemPage.getSize());
    }

    @Override
    public ProblemVO getProblemById(String id, String userId) {
        // 先从缓存获取
        String cacheKey = PROBLEM_CACHE_KEY + id;
        ProblemVO cachedProblem = (ProblemVO) redisTemplate.opsForValue().get(cacheKey);
        if (cachedProblem != null) {
            return cachedProblem;
        }

        Problem problem = getById(id);
        if (problem == null) {
            throw new BusinessException("问题不存在");
        }

        ProblemVO problemVO = convertToVO(problem, userId);
        
        // 缓存问题详情
        redisTemplate.opsForValue().set(cacheKey, problemVO, CACHE_EXPIRE_TIME, TimeUnit.MINUTES);
        
        return problemVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateProblem(String id, ProblemCreateDTO updateDTO) {
        Problem problem = getById(id);
        if (problem == null) {
            throw new BusinessException("问题不存在");
        }

        // 检查权限
        String currentUserId = UserContext.getUserId();
        if (!problem.getCreatorId().equals(currentUserId)) {
            throw new BusinessException("无权限修改此问题");
        }

        // 更新问题信息
        problem.setTitle(updateDTO.getTitle());
        problem.setDescription(updateDTO.getDescription());
        problem.setInputDescription(updateDTO.getInputDescription());
        problem.setOutputDescription(updateDTO.getOutputDescription());
        problem.setSampleInput(updateDTO.getSampleInput());
        problem.setSampleOutput(updateDTO.getSampleOutput());
        problem.setHint(updateDTO.getHint());
        problem.setSource(updateDTO.getSource());
        problem.setCategoryId(updateDTO.getCategoryId());
        problem.setDifficulty(updateDTO.getDifficulty());
        problem.setType(updateDTO.getType());
        problem.setTimeLimit(updateDTO.getTimeLimit());
        problem.setMemoryLimit(updateDTO.getMemoryLimit());
        problem.setIsSpecialJudge(updateDTO.getIsSpecialJudge());
        problem.setSpecialJudgeCode(updateDTO.getSpecialJudgeCode());
        problem.setIsPublic(updateDTO.getIsPublic());
        problem.setIsRecommend(updateDTO.getIsRecommend());
        problem.setSortOrder(updateDTO.getSortOrder());

        // 处理标签
        if (updateDTO.getTags() != null) {
            try {
                problem.setTags(objectMapper.writeValueAsString(updateDTO.getTags()));
            } catch (JsonProcessingException e) {
                log.error("标签序列化失败", e);
            }
        }

        // 处理支持的编程语言
        if (updateDTO.getSupportedLanguages() != null) {
            try {
                problem.setSupportedLanguages(objectMapper.writeValueAsString(updateDTO.getSupportedLanguages()));
            } catch (JsonProcessingException e) {
                log.error("支持语言序列化失败", e);
            }
        }

        boolean updated = updateById(problem);
        if (updated) {
            // 清除缓存
            clearProblemCache(id);
            log.info("用户 {} 更新了问题 {}", UserContext.getUsername(), problem.getTitle());
        }
        
        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteProblem(String id) {
        Problem problem = getById(id);
        if (problem == null) {
            throw new BusinessException("问题不存在");
        }

        // 检查权限
        String currentUserId = UserContext.getUserId();
        if (!problem.getCreatorId().equals(currentUserId)) {
            throw new BusinessException("无权限删除此问题");
        }

        boolean deleted = removeById(id);
        if (deleted) {
            // 清除缓存
            clearProblemCache(id);
            log.info("用户 {} 删除了问题 {}", UserContext.getUsername(), problem.getTitle());
        }
        
        return deleted;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean publishProblem(String id) {
        Problem problem = getById(id);
        if (problem == null) {
            throw new BusinessException("问题不存在");
        }

        // 检查权限
        String currentUserId = UserContext.getUserId();
        if (!problem.getCreatorId().equals(currentUserId)) {
            throw new BusinessException("无权限发布此问题");
        }

        problem.setStatus(1); // 已发布
        
        boolean updated = updateById(problem);
        if (updated) {
            // 清除缓存
            clearProblemCache(id);
            log.info("用户 {} 发布了问题 {}", UserContext.getUsername(), problem.getTitle());
        }
        
        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean unpublishProblem(String id) {
        Problem problem = getById(id);
        if (problem == null) {
            throw new BusinessException("问题不存在");
        }

        // 检查权限
        String currentUserId = UserContext.getUserId();
        if (!problem.getCreatorId().equals(currentUserId)) {
            throw new BusinessException("无权限下架此问题");
        }

        problem.setStatus(2); // 已下架
        
        boolean updated = updateById(problem);
        if (updated) {
            // 清除缓存
            clearProblemCache(id);
            log.info("用户 {} 下架了问题 {}", UserContext.getUsername(), problem.getTitle());
        }
        
        return updated;
    }

    @Override
    public Boolean reviewProblem(String id, Boolean approved, String comment) {
        Problem problem = getById(id);
        if (problem == null) {
            throw new BusinessException("问题不存在");
        }

        String currentUserId = UserContext.getUserId();
        String currentUserName = UserContext.getUsername();

        problem.setReviewerId(currentUserId);
        problem.setReviewerName(currentUserName);
        problem.setReviewComment(comment);
        
        if (approved) {
            problem.setStatus(1); // 审核通过，已发布
        } else {
            problem.setStatus(4); // 审核失败
        }

        boolean updated = updateById(problem);
        if (updated) {
            clearProblemCache(id);
            log.info("用户 {} 审核了问题 {}，结果：{}", currentUserName, problem.getTitle(), approved ? "通过" : "失败");
        }
        
        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateProblemStatus(String id, String status) {
        Problem problem = getById(id);
        if (problem == null) {
            throw new BusinessException("问题不存在");
        }

        // 检查权限
        String currentUserId = UserContext.getUserId();
        if (!problem.getCreatorId().equals(currentUserId)) {
            throw new BusinessException("无权限修改此问题状态");
        }

        // 根据状态字符串设置状态值
        Integer statusValue = switch (status.toUpperCase()) {
            case "DRAFT" -> 0;
            case "PUBLISHED" -> 1;
            case "UNPUBLISHED" -> 2;
            case "REVIEWING" -> 3;
            case "REJECTED" -> 4;
            default -> throw new BusinessException("无效的状态值: " + status);
        };

        problem.setStatus(statusValue);

        boolean updated = updateById(problem);
        if (updated) {
            // 清除缓存
            clearProblemCache(id);
            log.info("用户 {} 更新了问题 {} 的状态为 {}", UserContext.getUsername(), problem.getTitle(), status);
        }

        return updated;
    }

    @Override
    public List<ProblemVO> getRecommendProblems(String userId, Integer difficulty, Integer limit) {
        List<Problem> problems = problemMapper.selectRecommendProblems(userId, difficulty, limit);
        return problems.stream()
                .map(problem -> convertToVO(problem, userId))
                .toList();
    }

    @Override
    public List<ProblemVO> getHotProblems(Integer limit) {
        // 先从缓存获取
        List<ProblemVO> cachedProblems = (List<ProblemVO>) redisTemplate.opsForValue().get(HOT_PROBLEMS_CACHE_KEY);
        if (cachedProblems != null && !cachedProblems.isEmpty()) {
            return cachedProblems.stream().limit(limit).toList();
        }

        List<Problem> problems = problemMapper.selectHotProblems(limit);
        String currentUserId = UserContext.getUserId();
        List<ProblemVO> result = problems.stream()
                .map(problem -> convertToVO(problem, currentUserId))
                .toList();
        
        // 缓存热门问题
        redisTemplate.opsForValue().set(HOT_PROBLEMS_CACHE_KEY, result, 10, TimeUnit.MINUTES);
        
        return result;
    }

    @Override
    public List<ProblemVO> getRelatedProblems(String problemId, Integer limit) {
        List<Problem> problems = problemMapper.selectRelatedProblems(problemId, limit);
        String currentUserId = UserContext.getUserId();
        return problems.stream()
                .map(problem -> convertToVO(problem, currentUserId))
                .toList();
    }

    @Override
    public List<ProblemVO> getProblemsByTags(List<String> tags, Integer limit) {
        List<Problem> problems = problemMapper.selectProblemsByTags(tags, limit);
        String currentUserId = UserContext.getUserId();
        return problems.stream()
                .map(problem -> convertToVO(problem, currentUserId))
                .toList();
    }

    @Override
    public List<ProblemVO> searchProblems(String keyword, Integer limit) {
        List<Problem> problems = problemMapper.searchProblems(keyword, limit);
        String currentUserId = UserContext.getUserId();
        return problems.stream()
                .map(problem -> convertToVO(problem, currentUserId))
                .toList();
    }

    @Override
    public Boolean updateProblemStatistics(String problemId, Long submitCount, Long acceptCount) {
        int updated = problemMapper.updateStatistics(problemId, submitCount, acceptCount);
        if (updated > 0) {
            clearProblemCache(problemId);
        }
        return updated > 0;
    }

    @Override
    public Boolean updateProblemAvgPerformance(String problemId, Integer avgTime, Integer avgMemory) {
        int updated = problemMapper.updateAvgPerformance(problemId, avgTime, avgMemory);
        if (updated > 0) {
            clearProblemCache(problemId);
        }
        return updated > 0;
    }

    @Override
    public ProblemStatistics getProblemStatistics(String categoryId, Integer difficulty) {
        return problemMapper.selectProblemStatistics(categoryId, difficulty);
    }

    @Override
    public List<TagStatistics> getHotTags(Integer limit) {
        return problemMapper.selectHotTags(limit);
    }

    @Override
    public UserSolveStatistics getUserSolveStatistics(String userId) {
        return problemMapper.selectUserSolveStatistics(userId);
    }

    @Override
    public List<ProblemVO> getDailyChallenges(String userId, Integer count) {
        String date = LocalDate.now().toString();
        List<Problem> problems = problemMapper.selectDailyChallenges(userId, date, count);
        return problems.stream()
                .map(problem -> convertToVO(problem, userId))
                .toList();
    }

    @Override
    public Boolean favoriteProblem(String problemId, String userId) {
        // 这里应该实现收藏逻辑，可能需要创建收藏表
        // 简化处理，返回true
        return true;
    }

    @Override
    public Boolean unfavoriteProblem(String problemId, String userId) {
        // 这里应该实现取消收藏逻辑
        // 简化处理，返回true
        return true;
    }

    @Override
    public List<ProblemVO> getUserFavoriteProblems(String userId, Integer limit) {
        // 这里应该查询用户收藏的问题
        // 简化处理，返回空列表
        return List.of();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer batchImportProblems(List<ProblemCreateDTO> problems) {
        int successCount = 0;
        for (ProblemCreateDTO problemDTO : problems) {
            try {
                createProblem(problemDTO);
                successCount++;
            } catch (Exception e) {
                log.error("导入问题失败：{}", problemDTO.getTitle(), e);
            }
        }
        return successCount;
    }

    @Override
    public List<ProblemVO> exportProblems(List<String> problemIds) {
        String currentUserId = UserContext.getUserId();
        return problemIds.stream()
                .map(id -> getProblemById(id, currentUserId))
                .toList();
    }

    /**
     * 转换为VO
     */
    private ProblemVO convertToVO(Problem problem, String userId) {
        ProblemVO vo = BeanCopyUtils.copyBean(problem, ProblemVO.class);
        
        // 设置额外信息
        setAdditionalInfo(vo);
        
        // 解析JSON字段
        parseJsonFields(vo, problem);
        
        // 设置用户相关信息
        if (StringUtils.hasText(userId)) {
            setUserRelatedInfo(vo, userId);
        }
        
        return vo;
    }

    /**
     * 设置额外信息
     */
    private void setAdditionalInfo(ProblemVO vo) {
        // 设置难度名称
        switch (vo.getDifficulty()) {
            case 1 -> vo.setDifficultyName("简单");
            case 2 -> vo.setDifficultyName("中等");
            case 3 -> vo.setDifficultyName("困难");
            case 4 -> vo.setDifficultyName("专家");
            default -> vo.setDifficultyName("未知");
        }
        
        // 设置类型名称
        switch (vo.getType()) {
            case 1 -> vo.setTypeName("算法");
            case 2 -> vo.setTypeName("数据结构");
            case 3 -> vo.setTypeName("数学");
            case 4 -> vo.setTypeName("字符串");
            case 5 -> vo.setTypeName("动态规划");
            case 6 -> vo.setTypeName("图论");
            default -> vo.setTypeName("其他");
        }
        
        // 设置状态名称
        switch (vo.getStatus()) {
            case 0 -> vo.setStatusName("草稿");
            case 1 -> vo.setStatusName("已发布");
            case 2 -> vo.setStatusName("已下架");
            case 3 -> vo.setStatusName("审核中");
            default -> vo.setStatusName("未知");
        }
    }

    /**
     * 解析JSON字段
     */
    private void parseJsonFields(ProblemVO vo, Problem problem) {
        try {
            if (StringUtils.hasText(problem.getTags())) {
                vo.setTags(objectMapper.readValue(problem.getTags(), List.class));
            }
            if (StringUtils.hasText(problem.getSupportedLanguages())) {
                vo.setSupportedLanguages(objectMapper.readValue(problem.getSupportedLanguages(), List.class));
            }
        } catch (JsonProcessingException e) {
            log.error("解析JSON字段失败", e);
        }
    }

    /**
     * 设置用户相关信息
     */
    private void setUserRelatedInfo(ProblemVO vo, String userId) {
        // 这里可以查询用户解题状态、收藏状态等
        // 为了简化，暂时设置默认值
        vo.setUserStatus(0); // 未尝试
        vo.setUserBestScore(0);
        vo.setUserBestTime(0);
        vo.setUserSubmitCount(0);
        vo.setIsFavorite(false);
    }

    /**
     * 清除问题缓存
     */
    private void clearProblemCache(String problemId) {
        redisTemplate.delete(PROBLEM_CACHE_KEY + problemId);
        redisTemplate.delete(HOT_PROBLEMS_CACHE_KEY);
    }
}
